package com.szwistar.common.luaj;

import com.szwistar.common.datastruct.JsonMapper;

import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
import org.luaj.vm2.lib.OneArgFunction;
import org.luaj.vm2.lib.TwoArgFunction;
import org.luaj.vm2.lib.VarArgFunction;
import org.luaj.vm2.lib.ZeroArgFunction;
import org.luaj.vm2.lib.jse.CoerceLuaToJava;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;

public class LuaUtils extends TwoArgFunction {
	static final Logger LOG = LoggerFactory.getLogger(LuaUtils.class);
	static final Logger LOGLUA = LoggerFactory.getLogger("lua");

	/// 库加载时调用
	@Override
	public LuaValue call(LuaValue modname, LuaValue env) {
		LuaValue library = tableOf();
		library.set( "print", new JLFunc_print() );
		library.set( "currentTimeMillis", new JLFunc_currentTimeMillis() );
		library.set( "toJson", new JLFunc_toJson() );
		env.set( "utils", library );
		return library;
	}

	/// 实现 print 命令输出到日志
	public static class JLFunc_print extends VarArgFunction {
		@Override
		public Varargs invoke(Varargs args) {
			switch(args.narg()) {
				case 0: break;
				case 1: LOGLUA.info("{}",                                 args.arg(1)); break;
				case 2: LOGLUA.info("{}\t{}",                             args.arg(1), args.arg(2)); break;
				case 3: LOGLUA.info("{}\t{}\t{}",                         args.arg(1), args.arg(2), args.arg(3)); break;
				case 4: LOGLUA.info("{}\t{}\t{}\t{}",                     args.arg(1), args.arg(2), args.arg(3), args.arg(4)); break;
				case 5: LOGLUA.info("{}\t{}\t{}\t{}\t{}",                 args.arg(1), args.arg(2), args.arg(3), args.arg(4), args.arg(5)); break;
				case 6: LOGLUA.info("{}\t{}\t{}\t{}\t{}\t{}",             args.arg(1), args.arg(2), args.arg(3), args.arg(4), args.arg(5), args.arg(6)); break;
				case 7: LOGLUA.info("{}\t{}\t{}\t{}\t{}\t{}\t{}",         args.arg(1), args.arg(2), args.arg(3), args.arg(4), args.arg(5), args.arg(6), args.arg(7)); break;
				case 8: LOGLUA.info("{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}",     args.arg(1), args.arg(2), args.arg(3), args.arg(4), args.arg(5), args.arg(6), args.arg(7), args.arg(8)); break;
				default:
				case 9: LOGLUA.info("{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}", args.arg(1), args.arg(2), args.arg(3), args.arg(4), args.arg(5), args.arg(6), args.arg(7), args.arg(8), args.arg(9)); break;
			}

			// 没有返回值时，要返回 LuaValue.NONE/LuaValue.NIL，而不是 null ！
			return NONE; // NIL;
		}
	}

	/// 获取当前时间: 1970年1月1日到现在的毫秒数
	public static class JLFunc_currentTimeMillis extends ZeroArgFunction {
        @Override
        public LuaValue call() {
            return valueOf(System.currentTimeMillis());
        }
    }

	/// 把对象转换为 JSON
	public static class JLFunc_toJson extends OneArgFunction {
		@Override
		public LuaValue call(LuaValue arg) {
			return valueOf(toJson(arg));
		}
    }

	public static Object toJava(LuaValue arg) {
		if(arg == null) { return null; }
		if(arg instanceof LuaTable) {
			LuaTable tab = (LuaTable) arg;
			int arrayItemCount = tab.length();
			int hashItemCount = tab.keyCount();
			return (hashItemCount > arrayItemCount) ? tableToMap(tab) : tableToArray(tab);
		}
		return CoerceLuaToJava.coerce(arg, Object.class);
	}

	public static Map<String, Object> tableToMap(LuaTable tab) {
		Map<String, Object> map = new HashMap<String, Object>();
		LuaValue key = LuaValue.NIL;
		while(true) {
			Varargs pair = tab.next(key);
			if(pair == LuaValue.NIL) { break; }
			key = pair.arg1();
			LuaValue val = pair.arg(2);
			map.put(key.tojstring(), toJava(val));
		}
		return map;
	}

	public static Object[] tableToArray(LuaTable tab) {
		int len = tab.length();
		Object[] array = new Object[len];
		for(int i=0; i<len; i++) {
			array[i] = toJava(tab.get(i+1));
		}
		return array;
	}

	public static String toJson(LuaValue arg) {
		try {
			Object obj = toJava(arg);
			return JsonMapper.toJson(obj);
		} catch (Exception e) {
			return null;
		}
	}
}
